﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text.RegularExpressions;

namespace Tambourine.Model
{
    /// <summary>
    /// Presents single pivot table;
    /// </summary>
    public class TestCortegeMatrix : ObservableCollection<TestCortege>, IList, ITypedList
    {
        enum DataColumnType
        {
            leftSideColumn,
            pivotColumn,
            rightSideColumn
        }

        class DataCulumn
        {
            public string Name { get; private set; }
            public int? Position { get; private set; }
            public DataColumnType Type { get; private set; }

            public DataCulumn(string name, DataColumnType type, int? position = null)
            {
                Name = name; Position = position; Type = type;
            }
        }

        #region model
        public TestCortegeMatrix() { }

        public TestCortegeMatrix(string name, bool isSuccessful, bool wasExecuted, string argumentList, string pivotArgument)
        {
            Name = name;
            IsSuccessful = isSuccessful;
            WasExecuted = wasExecuted;

            Columns = new List<DataCulumn>();
            PivotColumn = null;

            string[] arguments = argumentList.Split(',');
            for (int i = 0; i < arguments.Count(); i++)
                if (arguments[i] == pivotArgument)
                    PivotColumn = new DataCulumn(arguments[i], DataColumnType.pivotColumn, i);
                else
                    Columns.Add(new DataCulumn(arguments[i], DataColumnType.leftSideColumn, i));

            if (PivotColumn == null)
                throw new ArgumentException("pivotArgument");
        }

        public string Name { get; private set; }
        public bool IsSuccessful { get; private set; }
        public bool WasExecuted { get; private set; }

        List<DataCulumn> Columns;
        DataCulumn PivotColumn;

        public void AddTestResult(string rawTestName, TestResult testResult)
        {
            bool cortegeWasFound = false;
            TestCortege newCortege = createCortegeFromResult(rawTestName, testResult);
            foreach (TestCortege cortege in this)
                if (cortegesAreIdenticalByLeftSide(cortege, newCortege))
                {
                    combineCortegesRightSide(cortege, newCortege);
                    cortegeWasFound = true;
                }
            if (!cortegeWasFound)
                this.Add(newCortege);
        }

        TestCortege createCortegeFromResult(string rawTestName, TestResult testResult)
        {
            string[] argumentValues = GetFirstRegExpMatch(rawTestName, @"\((.*)\)").Replace("\"", "").Split(',');

            TestCortege cortege = new TestCortege();
            for (int i = 0; i < argumentValues.Count(); i++)
                if (i == PivotColumn.Position)
                {
                    if (!Columns.Any(a => a.Type == DataColumnType.rightSideColumn && a.Name == argumentValues[i]))
                        Columns.Add(new DataCulumn(argumentValues[i], DataColumnType.rightSideColumn));
                    cortege[argumentValues[i]] = testResult;
                }
                else
                {
                    string columnName = Columns.First(a => a.Position == i).Name;
                    cortege[columnName] = argumentValues[i];
                }

            return cortege;
        }

        bool cortegesAreIdenticalByLeftSide(TestCortege left, TestCortege right)
        {
            string[] leftSideColumns = Columns.Where(a => a.Type == DataColumnType.leftSideColumn).Select(a => a.Name).ToArray();
            foreach (string leftSideElement in leftSideColumns)
                if ((string)left[leftSideElement] != (string)right[leftSideElement])
                    return false;
            return true;
        }

        void combineCortegesRightSide(TestCortege dstCortege, TestCortege srcCortege)
        {
            foreach (string rightSideElement in Columns.Where(a => a.Type == DataColumnType.rightSideColumn).Select(a => a.Name))
                if (dstCortege[rightSideElement] == null && srcCortege[rightSideElement] != null)
                    dstCortege[rightSideElement] = srcCortege[rightSideElement];
        }

        string GetFirstRegExpMatch(string inputString, string searchPattern)
        {
            Match strMatch = Regex.Match(inputString, searchPattern, RegexOptions.IgnoreCase);

            string retValue = null;
            if (strMatch.Success)
                retValue = strMatch.Groups[1].Value;

            return retValue;
        }
        #endregion model

        #region ITypedList
        public PropertyDescriptorCollection GetItemProperties(PropertyDescriptor[] listAccessors)
        {
            if (this.Any())
            {
                ICustomTypeDescriptor firstItem = this[0] as ICustomTypeDescriptor;
                if (firstItem != null)
                    return firstItem.GetProperties();
            }

            return TypeDescriptor.GetProperties(typeof(TestCortege), new Attribute[] { new BrowsableAttribute(true) });
        }

        public string GetListName(PropertyDescriptor[] listAccessors)
        {
            return null;
        }
        #endregion ITypedList
    }
}
